from invidious import *

from ui.cli_progress import printProgressBar
from ui.progressbar import ProgressBar
from ui.linepicker import pick
from ui.input import ninput

from src.vobjects.userplaylists import UserPlaylists
from src.vobjects.basechannel import BaseChannel
from src.vobjects.playlist import Playlist
from src.vobjects.channel import Channel
from src.vobjects.player import Player
from src.vobjects.video import Video
from src.vobjects.item import Item

from src.content_manager import ContentManager
from src.database import Database
from src.history import History
from src.config import Config
from src.utils import *

from plugins.core.plugman import PlugMan
from plugins.core.plugin import Plugin
from plugins.core.pluginvideo import PluginVideo
from plugins.core.pluginplaylist import PluginPlaylist

from multiprocessing.pool import ThreadPool
from threading import Thread
from os.path import exists
import argparse
import operator
import sys, os
import datetime
import json
import time

class Rosen():

    def __init__(self):
        self.version    = "0.6.0"
        self.config     = Config()
        self.database   = Database()

        self.history    = History()
        self.playlists  = UserPlaylists()

        self.plugman = PlugMan(self.history)
        self.plugman.load_user_plugins()
        self.plugman.load_plugins()

        self.invidious = Invidious(isLoggerEnabled=False)

        self.app_title      = "Rosen"
        self.history_title  = "Rosen: History"
        self.vmenu_title    = "Rosen: VMenu"

    def print_version(self):
        print(f"Rosen v{self.version}")

    def print_stats(self):
        watched_time_sec, plugin_videos, videos = 0,0,0

        for video in self.history.video_list:
            watched_time_sec += video.watched_time
            if type(video) == PluginVideo: plugin_videos += 1
            else: videos += 1

        watched_time = datetime.timedelta(seconds=watched_time_sec)
        total_videos = plugin_videos + videos

        print(f"You watched {total_videos} videos ({plugin_videos} plugin videos and {videos} videos)")
        print(f"And burn {watched_time_sec} seconds ({watched_time}) of your life.")

    def display_video_menu(self, from_playlist: bool=False):
        if not self.config.ShowVideoMenu: return "VA"

        items = [
            Item(title="Video and Audio",       parent="VA"),
            Item(title="Only video",            parent="V"),
            Item(title="Only audio",            parent="A"),
            Item(title="Download",              parent="DW"),
            Item(title="Download (Audio only)", parent="DWA"),
            Item(title="Add to playlist",       parent="AP")
        ]
        
        if from_playlist: 
            items.append(Item(title="Remove from playlist", parent="RP"))

        item, index = pick(self.vmenu_title, items)
        if index == -1: return

        if type(item) is list: item = item[0]

        return item.parent

    def display_video_time_menu(self):
        items = [
            Item(title="Play from start", parent="PS"),
            Item(title="Continue",        parent="CN")
        ]

        item, index = pick(self.vmenu_title, items)
        if index == -1: return

        if type(item) is list: item = item[0]

        return item.parent

    def play_video(self, video, from_playlist: bool=False, playlist=None):
        option = self.display_video_menu(from_playlist=from_playlist)
        if option != "DW" and from_playlist == False and video.watched_time != 0: time_opt = self.display_video_time_menu()
        else: time_opt = None

        video_url = get_video_url(video, self.invidious.get_working_mirror())

        if option == "DW": ContentManager.download(video.title, video_url)
        elif option == "DWA": ContentManager.download(video.title, video_url, True)
        elif option == "AP":
            playlist = self.display_playlists(isAdder=True)
            self.playlists.insert(playlist.name, video)
        elif option == "RP":
            self.playlists.remove(playlist.name, video)
        elif option != None:
            if playlist != None:
                playlist.play(video=video, play_option=option, mirror=self.invidious.get_working_mirror())
            else:
                video.play(play_option=option, mirror=self.invidious.get_working_mirror(),
                           history=self.history, time_opt=time_opt)    

    def play_playlist(self, playlist: Playlist):
        option = self.display_video_menu()
        if option != None:
            playlist.play(play_option=option, mirror=self.invidious.get_working_mirror()) 

    def play_url_list(self, urls: list):
        option = self.display_video_menu()
        if option != None:
            player = Player()
            player.play_url_list(urls, option)

    def display_channel(self, channelId: str, index: int=0, channel: Channel=None,
                        channelUrl: str=None):
        if channelUrl != None:
            cstr = "channel/"
            channelId = channelUrl[channelUrl.find(cstr)+len(cstr):]
        if channel == None: 
            channel = self.invidious.get_channel(channelId)

        items = []
        for video in channel.latestVideos:
            if video == None: continue
            video.convert(Video)
            video.url = self.invidious.get_working_mirror() + "/watch?v=" + video.videoId
            inHistory = video.in_history(self.history)
            item = video.to_item(inHistory=inHistory)
            items.append(item)

        title = f"{self.app_title} - {channel.author}"
        item, index = pick(title, items, index=index)
        if index == -1: return

        if type(item) is list: 
            urls = self.get_items_urls(item)
            self.play_url_list(urls)
        else:
            self.play_video(item.parent)

        self.display_channel(channelId, index=index)      

    def load_video(self, url: str=""):
        wstr    = "watch?v="
        findex  = url.find(wstr)
        if findex == -1: wstr = "youtu.be/"; findex = url.find(wstr)
        videoId = url[findex+len(wstr):]
        video   = self.invidious.get_video(videoId)
        
        if video is None:
            print("Error: Incorrect url!"); exit(1)

        video.convert(Video)
        
        self.play_video(video)

        self.display_menu()

    def display_history(self, index: int=0):
        items = []
        for video in self.history.video_list:
            if type(video) == PluginVideo:
                item = video.to_item(inHistory=True)
            else: item = video.to_item(inHistory=True, isHistoryList=True)
            
            items.append(item)

        item, index = pick(self.history_title, items, index=index)
        if index == -1: return

        if type(item) is list:
            urls = self.get_items_urls(item)
            self.play_url_list(urls)
        else:
            if type(item.parent) == PluginVideo: 
                self.history.insert(item.parent)
                item.parent.play()
            else: self.play_video(item.parent)

        self.display_history(index=index) 

    def display_playlist(self, playlist, index: int=0):
        items = [
            Item(title="Remove", subtitle="[#]")
        ]
        for video in playlist.videos:
            item = video.to_item()
            items.append(item)
        
        item, index = pick(self.app_title, items, index=index)
        if index == -1: return

        if type(item) is list: item = item[0]

        if item.title == "Remove" and index == 0: 
            return self.playlists.remove_playlist(playlist.name)
        else: self.play_video(item.parent, from_playlist=True, playlist=playlist)

        ln = len(playlist.videos)-1
        if index > ln: index = ln

        self.display_playlist(playlist=playlist, index=index)

    def display_playlists(self, index: int=0, isAdder=False):
        items = [
            Item(title="New", subtitle="[#]")
        ]
        for playlist in self.playlists.playlists:
            item = playlist.to_item()
            items.append(item)

        item, index = pick(self.app_title, items, index=index)
        if index == -1: return
       
        if type(item) is list: item = item[0]

        if item.title == "New" and index == 0:
            pname = ninput(title="Input playlist name: ",
                           length=100, app_title=self.app_title)
            self.playlists.new(pname, [])
        else:
            if not isAdder: self.display_playlist(item.parent)
            else: return item.parent

        self.display_playlists(index=index)

    def get_items_urls(self, items: list):
        urls = list()
        for it in items:
            if hasattr(it.parent, 'url'): urls.append(it.parent.url)
            elif hasattr(it.parent, 'videoId'): 
                urls.append(self.invidious.get_working_mirror() + "/watch?v=" + it.parent.videoId)
        return urls

    def display_query_plugin(self, plugin, query=""):
        if query == "":
            query = ninput(title="Input your search query: ", length=100,
                       app_title=plugin.name, description=plugin.query_description)
        items = plugin.get_items_by_query(query)

        self.display_plugin_items(plugin=plugin, items=items)

    def display_plugin_playlist(self, playlist, index=0):
        item, index = pick(playlist.title, playlist.videos, index=index)
        if index == -1: return

        # is item - list
        if type(item) is list:
            urls = self.get_items_urls(item)
            self.play_url_list(urls)
        else:
            item.subtitle = '[+]'
            self.play_video(item.parent)

        self.display_plugin_playlist(playlist, index)

    def display_plugin_items(self, plugin, items, index=0):
        item, index = pick(plugin.name, items, index=index)
        if index == -1: return

        if type(item) is list:
            is_list = True
            prt = item[0].parent
        else:
            is_list = False
            prt = item.parent

        if type(prt) == PluginPlaylist: self.display_plugin_playlist(prt)
        elif type(prt) in [PluginVideo, Video]: 
            if is_list:
                urls = self.get_items_urls(item)
                self.play_url_list(urls)
            else:
                item.subtitle = '[+]'
                self.play_video(prt)
        elif type(prt) == BaseChannel: self.display_channel(prt.authorId, channel=prt)
        elif type(prt) == Channel: self.display_channel(prt.authorId)
        elif type(prt) == Playlist: self.play_playlist(prt)

        self.display_plugin_items(plugin, items, index)

    def display_menu(self, index: int=0):
        items = [
            Item(title="History"),
            Item(title="Playlists", subtitle='[b]')
        ]

        plugins = []
        for plugin in self.plugman.plugins:
            plugins.append(Item(title=plugin.name, subtitle="[p]", parent=plugin))

        plugins.sort(key=lambda a: a.title)
        items += plugins

        item, index = pick(self.app_title, items, index)
        if index == -1: return

        # is item - list
        if type(item) is list: item = item[0]

        # is parent - plugin
        if issubclass(type(item.parent), Plugin):
            if item.parent.is_query_required:
                self.display_query_plugin(plugin=item.parent)
            else:
                self.display_plugin_items(plugin=item.parent, items=item.parent.get_items())
        
        if item.title == "History": self.display_history()
        elif item.title == "Playlists": self.display_playlists()

        self.display_menu(index=index)
    
    def install_default_plugins(self):
        if len(self.plugman.plugins) == 0:
            query = ninput(title="Do you wan't install default Invidious plugins? (y/n): ", length=1,
                       app_title=self.app_title)
            if query == "y": self.plugman.install_default_plugins()


